package com.radar.io;

import cn.hutool.core.io.FileUtil;
import com.radar.algorithm.Cacl;
import com.radar.algorithm.DenseLucaskanade;
import com.radar.algorithm.MathCommon;
import com.radar.algorithm.SemiLagrangian;
import com.radar.common.GisConstants;
import com.radar.common.ProductType;
import com.radar.exception.RadarDecodeError;
import com.radar.utils.BitConverter;
import com.radar.visualize.RasterMap;
import org.bytedeco.javacpp.indexer.Indexer;
import org.bytedeco.opencv.global.opencv_imgcodecs;
import org.bytedeco.opencv.global.opencv_imgproc;
import org.bytedeco.opencv.opencv_core.Mat;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;


public class LatLonRadar extends BaseRadr {

    public double[][] data;

    public double lons;
    public double lone;
    public double lats;
    public double late;

    @Override
    public void parse(String file) throws RadarDecodeError {
        byte[] bytes = FileUtil.readBytes(file);
        if (bytes.length < 180) {
            throw new RadarDecodeError("bytes length < 180");
        }
        lons = (int) BitConverter.toSingle(bytes, 184);
        lone = (int) BitConverter.toSingle(bytes, 192);
        lats = (int) BitConverter.toSingle(bytes, 180);
        late = (int) BitConverter.toSingle(bytes, 188);
        int y = BitConverter.toInt32(bytes, 204);
        int x = BitConverter.toInt32(bytes, 208);
        data = new double[y][x];
        short amp = BitConverter.toInt16(bytes, 230);
        short compmode = BitConverter.toInt16(bytes, 232);
        int index = 256;
        // 压缩方式
        if (compmode == 1) {
            while (index < bytes.length - 1) {
                int yy = BitConverter.toInt16(bytes, index);
                index += 2;
                int xx = BitConverter.toInt16(bytes, index);
                index += 2;
                int num = BitConverter.toInt16(bytes, index);
                index += 2;
                for (int i = 0; i < num; i++) {
                    int dbz = BitConverter.toInt16(bytes, index) / amp;
                    data[yy][xx + i] = dbz;
                    index += 2;
                }
            }
            // 非压缩方式
        } else if (compmode == 0) {
            int colIndex = 1;
            int rowIndex = 1;
            while (index < bytes.length - 1) {
                int dbz = BitConverter.toInt16(bytes, index) / amp;
                // 读完一行，换下一行
                if (colIndex > x) {
                    colIndex = 1;
                    rowIndex += 1;
                }
                data[rowIndex][colIndex] = dbz;
                colIndex++;
                index += 2;
            }
        }
    }

    public void drawItem(String outDir) throws IOException {
        FileUtil.mkdir(outDir);
        RasterMap rasterMap = new RasterMap(null);
        for (int i = 0; i < data.length; i++) {
            for (int j = 0; j < data[0].length; j++) {
                data[i][j] = data[i][j] < 5 ? GisConstants.UNDEF : data[i][j];
            }
        }
        data = Cacl.nineMedianFilter(data);
        data = Cacl.nineMedianFilter(data);
        data = Cacl.nineMedianFilter(data);
        BufferedImage bufferedImage = rasterMap.drawSingleRaster(data, new Color(0, 0, 0, 0));
        ImageIO.write(bufferedImage, "png", new File(outDir + File.separator + "CR.png"));
        bufferedImage = rasterMap.drawSingleRaster(data, ProductType.REFGRAY, new Color(0, 0, 0, 0));
        ImageIO.write(bufferedImage, "png", new File(outDir + File.separator + "CR_GRAY.png"));
    }

    public void forecastItem(String prePath, String outDir) throws IOException {
        drawItem(outDir);
        if (FileUtil.exist(prePath + File.separator + "CR_GRAY.png")) {
            // forecast
            Mat ff1 = opencv_imgcodecs.imread(prePath + File.separator + "CR_GRAY.png");
            Mat ff2 = opencv_imgcodecs.imread(outDir + File.separator + "CR_GRAY.png");
            Mat prvs = ff1.clone();
            Mat next = ff1.clone();
            opencv_imgproc.cvtColor(ff1, prvs, opencv_imgproc.COLOR_BGR2GRAY);
            opencv_imgproc.cvtColor(ff2, next, opencv_imgproc.COLOR_BGR2GRAY);
            int w = prvs.size().get(0);
            int h = prvs.size().get(1);
            double[][] pre = new double[h][w];
            double[][] nex = new double[h][w];
            Indexer indexer = prvs.createIndexer();
            Indexer indexer1 = next.createIndexer();
            for (int i = 0; i < h; i++) {
                for (int j = 0; j < w; j++) {
                    pre[i][j] = indexer.getDouble(i, j);
                    if (pre[i][j] == 255) {
                        pre[i][j] = 0;
                    }
                    nex[i][j] = indexer1.getDouble(i, j);
                    if (nex[i][j] == 255) {
                        nex[i][j] = 0;
                    }
                }
            }
            double[][][] cacl = DenseLucaskanade.cacl(new double[][][]{pre, nex});
            double[][] u = cacl[0];
            double[][] v = cacl[1];
            for (int i = 0; i < h; i++) {
                for (int j = 0; j < w; j++) {
                    u[i][j] = u[i][j] * 2;
                    v[i][j] = v[i][j] * 2;
                }
            }
            SemiLagrangian semiLagrangian = new SemiLagrangian();
            int t = 20;
            float[][][] extrapolate = semiLagrangian.extrapolate(MathCommon.doubleToFloat(data), MathCommon.doubleToFloat(u), MathCommon.doubleToFloat(v), t);
            for (int i = 0; i < t; i++) {
                BufferedImage bufferedImage;
                for (int j = 0; j < u.length; j++) {
                    for (int k = 0; k < u[0].length; k++) {
                        extrapolate[i][j][k] = extrapolate[i][j][k] == 0 || extrapolate[i][j][k] == Float.NaN ? GisConstants.UNDEF : extrapolate[i][j][k];
                    }
                }
                RasterMap rasterMap = new RasterMap(null);
                bufferedImage = rasterMap.drawSingleRaster(MathCommon.floatToDouble(extrapolate[i]), new Color(0, 0, 0, 0));
                ImageIO.write(bufferedImage, "png", new File(outDir + File.separator + "CR_" + (i + 1) + ".png"));
            }
        }
    }

    @Override
    public void dispose() {

    }

    public static void main(String[] args) throws Exception {
        String tmpDir = "E:\\data\\latlon\\radar\\";
        String outDir = "E:\\data\\latlon\\forecast\\";
        LatLonRadar radar = new LatLonRadar();

        radar.parse(tmpDir + "Z_RADA_C_BABJ_20210615061109_P_ACHN.CREF000.20210318.0300.latlon");
        radar.forecastItem(outDir + "202103180240", outDir + "202103180300");

        LatLonRadar radar1 = new LatLonRadar();
        radar1.parse(tmpDir + "Z_RADA_C_BABJ_20210615062009_P_ACHN.CREF000.20210318.0312.latlon");
        radar1.forecastItem(outDir + "202103180300", outDir + "202103180312");
//
//        LatLonRadar radar2 = new LatLonRadar();
//        radar2.parse(tmpDir + "Z_RADA_C_BABJ_20210428082308_P_ACHN.CREF000.20210428.081200.latlon");
//        radar2.forecastItem(outDir + "202104280800", outDir + "202104280812");
//
//        LatLonRadar radar11 = new LatLonRadar();
//        radar11.parse(tmpDir + "Z_RADA_C_BABJ_20210428082908_P_ACHN.CREF000.20210428.081800.latlon");
//        radar11.forecastItem(outDir + "202104280806", outDir + "202104280818");
//
//        LatLonRadar radar3 = new LatLonRadar();
//        radar3.parse(tmpDir + "Z_RADA_C_BABJ_20210428083508_P_ACHN.CREF000.20210428.082400.latlon");
//        radar3.forecastItem(outDir + "202104280812", outDir + "202104280824");
//
//        LatLonRadar radar4 = new LatLonRadar();
//        radar4.parse(tmpDir + "Z_RADA_C_BABJ_20210428084108_P_ACHN.CREF000.20210428.083000.latlon");
//        radar4.forecastItem(outDir + "202104280818", outDir + "202104280830");
//
//        LatLonRadar radar5 = new LatLonRadar();
//        radar5.parse(tmpDir + "Z_RADA_C_BABJ_20210428084707_P_ACHN.CREF000.20210428.083600.latlon");
//        radar5.forecastItem(outDir + "202104280824", outDir + "202104280836");
//
//        LatLonRadar radar6 = new LatLonRadar();
//        radar6.parse(tmpDir + "Z_RADA_C_BABJ_20210428085307_P_ACHN.CREF000.20210428.084200.latlon");
//        radar6.forecastItem(outDir + "202104280830", outDir + "202104280842");
//
//        LatLonRadar radar7 = new LatLonRadar();
//        radar7.parse(tmpDir + "Z_RADA_C_BABJ_20210428085908_P_ACHN.CREF000.20210428.084800.latlon");
//        radar7.forecastItem(outDir + "202104280836", outDir + "202104280848");
//
//        LatLonRadar radar8 = new LatLonRadar();
//        radar8.parse(tmpDir + "Z_RADA_C_BABJ_20210428090508_P_ACHN.CREF000.20210428.085400.latlon");
//        radar8.forecastItem(outDir + "202104280842", outDir + "202104280854");
//
//        LatLonRadar radar9 = new LatLonRadar();
//        radar9.parse(tmpDir + "Z_RADA_C_BABJ_20210428091108_P_ACHN.CREF000.20210428.090000.latlon");
//        radar9.forecastItem(outDir + "202104280848", outDir + "202104280900");
//
//        LatLonRadar radar10 = new LatLonRadar();
//        radar10.parse(tmpDir + "Z_RADA_C_BABJ_20210428091709_P_ACHN.CREF000.20210428.090600.latlon");
//        radar10.forecastItem(outDir + "202104280854", outDir + "202104280906");
//
//        LatLonRadar radar12 = new LatLonRadar();
//        radar12.parse(tmpDir + "Z_RADA_C_BABJ_20210428092309_P_ACHN.CREF000.20210428.091200.latlon");
//        radar12.forecastItem(outDir + "202104280900", outDir + "202104280912");
    }

}
